﻿using HDSmartCommunity.BUS;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Threading;
using HDSmartCommunity.Models;
using Newtonsoft.Json;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Timers;
using Timer = System.Timers.Timer;
using SixLabors.ImageSharp.Memory;
using System.Collections;
using NPOI.SS.Formula.Functions;
using Aspose.Cells.Charts;
using HDSmartCommunity.DAL;
using Microsoft.AspNetCore.Http;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Net.NetworkInformation;
using System.Security.Cryptography.Xml;
using System.Security.Policy;

namespace HDSmartCommunity.DevicePlatform
{
    public class ComPassDeviceSerialData
    {
        #region ttys0刷卡器
        public int workmode;
        public SerialPort myS0SerialPort_1 = new SerialPort();
        public string mac_add = string.Empty;
        public void OpenS0SerialPort(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            try
            {
                SetS0SerialPortConfig(portName, baudRate, parity, dataBits, stopBits);
                myS0SerialPort_1.Open();
            }
            catch (Exception e)
            {
                LogHelper.Log(e.ToString());
            }
        }

        private Timer SerialPortRecvTimerS0_1;
        private static int byteLength = 40960;
        public byte[] byteSerialPortRecvS0_1 = new byte[byteLength];
        public event EventHandler<SerialPort485_1RecvEventArgs> ReceivedDataEventS0_1;
        private static int pSerialPortRecv_S0_1 = 0;

        public class SerialPort485_1RecvEventArgs : EventArgs
        {
            /// <summary>
            /// 广播 收到的串口数据
            /// </summary>
            public readonly byte[] RecvData_485_1 = new byte[byteLength];

            /// <summary>
            /// 收到数据 的 长度
            /// </summary>
            public readonly int RecvDataLength_485_1;

            /// <summary>
            /// 将 收到的数据 转化成 待广播的数据
            /// </summary>
            public SerialPort485_1RecvEventArgs(byte[] recvData, int recvDataLength)
            {
                recvData.CopyTo(RecvData_485_1, 0);
                RecvDataLength_485_1 = recvDataLength;
            }
        }

        private void SetS0SerialPortConfig(string portName, int baudRate, int parity, int dataBits, int stopBits)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                portName = $"/dev/{portName}";
            }
            // 串口 参数设置
            myS0SerialPort_1.PortName = portName;
            myS0SerialPort_1.BaudRate = baudRate;
            switch (parity)
            {
                case 0:
                default:
                    myS0SerialPort_1.Parity = Parity.None;
                    break;
                case 1:
                    myS0SerialPort_1.Parity = Parity.Odd;
                    break;
                case 2:
                    myS0SerialPort_1.Parity = Parity.Even;
                    break;
                case 3:
                    myS0SerialPort_1.Parity = Parity.Mark;
                    break;
                case 4:
                    myS0SerialPort_1.Parity = Parity.Space;
                    break;
            }
            myS0SerialPort_1.DataBits = ((4 < dataBits) && (dataBits < 9)) ? dataBits : 8;
            switch (stopBits)
            {
                case 0:
                    myS0SerialPort_1.StopBits = StopBits.None;
                    break;
                case 1:
                default:
                    myS0SerialPort_1.StopBits = StopBits.One;
                    break;
                case 2:
                    myS0SerialPort_1.StopBits = StopBits.OnePointFive;
                    break;
                case 3:
                    myS0SerialPort_1.StopBits = StopBits.Two;
                    break;
            }
            //my485SerialPort_1.ReadTimeout = 200;
            myS0SerialPort_1.RtsEnable = true;
            myS0SerialPort_1.DataReceived += new SerialDataReceivedEventHandler(DataReceived_ttyS0);

            // 串口 接收数据处理定时器 参数设置
            SerialPortRecvTimerS0_1 = new System.Timers.Timer();
            SerialPortRecvTimerS0_1.Interval = 100;
            SerialPortRecvTimerS0_1.AutoReset = false;
            SerialPortRecvTimerS0_1.Elapsed += new ElapsedEventHandler(SPRecvTimer_Tick_ttyS0_1);
        }

        private void SPRecvTimer_Tick_ttyS0_1(object sender, EventArgs e)
        {
            byte[] TemporaryData = new byte[byteLength];
            int TemporaryDataLength = 0;

            if (ReceivedDataEventS0_1 != null)
            {
                byteSerialPortRecvS0_1.CopyTo(TemporaryData, 0);
                TemporaryDataLength = pSerialPortRecv_S0_1;

                ReceivedDataEventS0_1.Invoke(this, new SerialPort485_1RecvEventArgs(TemporaryData, TemporaryDataLength));
                // 数据处理完后，将指针指向数据头，等待接收新的数据
                pSerialPortRecv_S0_1 = 0;
            }
        }

        private void DataReceived_ttyS0(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPortRecvTimerS0_1.Stop();

            try
            {
                byte[] ReadBuf = new byte[myS0SerialPort_1.BytesToRead];
                if (pSerialPortRecv_S0_1 > byteLength - ReadBuf.Length)
                {
                    pSerialPortRecv_S0_1 = 0;
                }
                myS0SerialPort_1.Read(ReadBuf, 0, ReadBuf.Length);
                ReadBuf.CopyTo(byteSerialPortRecvS0_1, pSerialPortRecv_S0_1);
                pSerialPortRecv_S0_1 += ReadBuf.Length;
                SerialDataSaveLogHelper.Log(ToHexs(ReadBuf));
                LogHelper.Log("接收数据:" + ToHexs(ReadBuf));

                try
                {
                    for (int i = 0; i < byteSerialPortRecvS0_1.Length; i++)
                    {
                        if (byteSerialPortRecvS0_1[i] == 0xA1 && byteSerialPortRecvS0_1[i + 3] == 0x03 && byteSerialPortRecvS0_1[i + 7] == 0xD1)
                        {
                            byte[] data = new byte[5];
                            data[0] = byteSerialPortRecvS0_1[i + 1];
                            data[1] = byteSerialPortRecvS0_1[i + 2];
                            data[2] = byteSerialPortRecvS0_1[i + 3];
                            data[3] = byteSerialPortRecvS0_1[i + 4];
                            data[4] = byteSerialPortRecvS0_1[i + 5];
                            byte sum_data = ADD(data);
                            if (sum_data == byteSerialPortRecvS0_1[i + 6])
                            {
                                Array.Clear(byteSerialPortRecvS0_1, i, 8);
                                byte[] reply_data = new byte[8];
                                data[4] = Convert.ToByte(workmode == 1 ? 0 : 1);
                                Array.Copy(data, 0, reply_data, 1, 5);
                                reply_data[0] = 0xA1;
                                reply_data[6] = ADD(data);
                                reply_data[7] = 0xD1;
                                ttySendMsg(reply_data);
                            }
                        }
                        else if (byteSerialPortRecvS0_1[i] == 0xA1 && byteSerialPortRecvS0_1[i + 3] == 0x06 && byteSerialPortRecvS0_1[i + 10] == 0xD1)
                        {
                            bool insert_flag = false;
                            byte[] data = new byte[8];
                            data[0] = byteSerialPortRecvS0_1[i + 1];
                            data[1] = byteSerialPortRecvS0_1[i + 2];
                            data[2] = byteSerialPortRecvS0_1[i + 3];
                            data[3] = byteSerialPortRecvS0_1[i + 4];
                            data[4] = byteSerialPortRecvS0_1[i + 5];
                            data[5] = byteSerialPortRecvS0_1[i + 6];
                            data[6] = byteSerialPortRecvS0_1[i + 7];
                            data[7] = byteSerialPortRecvS0_1[i + 8];
                            byte sum_data = ADD(data);
                            if (sum_data == byteSerialPortRecvS0_1[i + 9])
                            {
                                Array.Clear(byteSerialPortRecvS0_1, i, 11);

                                byte[] sumcheck_data = new byte[24] {
                                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0D,0x00,0x00};
                                List<OwnerInfo> ownerInfos = new List<OwnerInfo>();
                                long cardno = 0;
                                sumcheck_data[0] = data[0];
                                sumcheck_data[1] = data[1];
                                sumcheck_data[2] = data[2];
                                sumcheck_data[3] = data[3];

                                try
                                {
                                    byte[] card_data = new byte[8];
                                    card_data[0] = data[4];
                                    card_data[1] = data[5];
                                    card_data[2] = data[6];
                                    card_data[3] = data[7];
                                    card_data[4] = 0x00;
                                    card_data[5] = 0x00;
                                    card_data[6] = 0x00;
                                    card_data[7] = 0x00;
                                    cardno = BitConverter.ToInt64(card_data, 0);
                                    CardInfoDAL cardInfoDAL = new CardInfoDAL();
                                    ownerInfos = cardInfoDAL.QueryCard(cardno.ToString());
                                    if (ownerInfos != null && ownerInfos.Count > 0)
                                    {
                                        if (ownerInfos[0].startTime <= DateTime.Now && ownerInfos[0].endTime >= DateTime.Now)
                                        {
                                            sumcheck_data[4] = 0x01;
                                            sumcheck_data[5] = Convert.ToByte(ownerInfos[0].personType);
                                            byte[] front_bytes = HexStringToByteArray(ownerInfos[0].frontFloor);
                                            byte[] back_bytes = HexStringToByteArray(ownerInfos[0].backFloor);
                                            int front_num = GetFloorNum(front_bytes);
                                            int back_num = GetFloorNum(back_bytes);
                                            if (front_num > 1)
                                            {
                                                sumcheck_data[6] = 0x01;
                                            }
                                            else
                                            {
                                                sumcheck_data[6] = 0x00;
                                            }
                                            Array.Copy(front_bytes, 0, sumcheck_data, 7, 8);

                                            if (back_num > 1)
                                            {
                                                sumcheck_data[15] = 0x01;
                                            }
                                            else
                                            {
                                                sumcheck_data[15] = 0x00;
                                            }
                                            Array.Copy(back_bytes, 0, sumcheck_data, 16, 8);
                                        }
                                        else
                                        {
                                            sumcheck_data[4] = 0x03;
                                        }
                                    }
                                    else
                                    {
                                        PushInfo pushInfo = new PushInfo();
                                        pushInfo.cardNO = cardno.ToString();
                                        pushInfo.deviceID = mac_add;
                                        string url = string.Format("http://{0}:{1}/api/cems/PushInfo", compass_add, compass_port);
                                        string msg = HttpClientPost(url, pushInfo);
                                        LogHelper.Log("获取卡信息" + msg);
                                        PushInfoReturn pushInfoReturn = JsonConvert.DeserializeObject<PushInfoReturn>(msg);
                                        if (pushInfoReturn != null && pushInfoReturn.errcode == 0 && !string.IsNullOrEmpty(pushInfoReturn.data.cardNO) && pushInfoReturn.data.stateID != 7)
                                        {
                                            insert_flag = true;

                                            OwnerInfo ownerInfo = new OwnerInfo();
                                            ownerInfo.personName = pushInfoReturn.data.personName;
                                            ownerInfo.personID = pushInfoReturn.data.personID;
                                            ownerInfo.frontFloor = pushInfoReturn.data.frontFloor;
                                            ownerInfo.backFloor = pushInfoReturn.data.backFloor;
                                            ownerInfo.personType = pushInfoReturn.data.personType;
                                            ownerInfo.personName = pushInfoReturn.data.personName;
                                            ownerInfo.sex = pushInfoReturn.data.sex;
                                            ownerInfo.cardNo = pushInfoReturn.data.cardNO;
                                            ownerInfo.frontFloor = pushInfoReturn.data.frontFloor;
                                            ownerInfo.backFloor = pushInfoReturn.data.backFloor;
                                            ownerInfo.startTime = Convert.ToDateTime(pushInfoReturn.data.startTime);
                                            ownerInfo.endTime = Convert.ToDateTime(pushInfoReturn.data.endTime);
                                            ownerInfo.personID = pushInfoReturn.data.personID;
                                            ownerInfos.Add(ownerInfo);

                                            if (Convert.ToDateTime(pushInfoReturn.data.startTime) <= DateTime.Now && Convert.ToDateTime(pushInfoReturn.data.endTime) >= DateTime.Now)
                                            {
                                                sumcheck_data[4] = 0x01;
                                                sumcheck_data[5] = Convert.ToByte(pushInfoReturn.data.personType);
                                                byte[] front_bytes = HexStringToByteArray(pushInfoReturn.data.frontFloor);
                                                byte[] back_bytes = HexStringToByteArray(pushInfoReturn.data.backFloor);
                                                int front_num = GetFloorNum(front_bytes);
                                                int back_num = GetFloorNum(back_bytes);
                                                if (front_num > 1)
                                                {
                                                    sumcheck_data[6] = 0x01;
                                                }
                                                else
                                                {
                                                    sumcheck_data[6] = 0x00;
                                                }
                                                Array.Copy(front_bytes, 0, sumcheck_data, 7, 8);

                                                if (back_num > 1)
                                                {
                                                    sumcheck_data[15] = 0x01;
                                                }
                                                else
                                                {
                                                    sumcheck_data[15] = 0x00;
                                                }
                                                Array.Copy(back_bytes, 0, sumcheck_data, 16, 8);
                                            }
                                            else
                                            {
                                                sumcheck_data[4] = 0x03;
                                            }
                                        }
                                        else
                                        {
                                            sumcheck_data[4] = 0x02;
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    sumcheck_data[4] = 0x00;
                                }
                                byte[] bytes = new byte[27];
                                Array.Copy(sumcheck_data, 0, bytes, 1, 24);
                                bytes[0] = 0xA1;
                                bytes[25] = ADD(sumcheck_data);
                                bytes[26] = 0xD1;
                                ttySendMsg(bytes);

                                try
                                {
                                    PushInfo info_insert = new PushInfo();
                                    info_insert.deviceID = "";
                                    info_insert.cardNO = string.Format("业主姓名:{0},业主Id{5},设备:{1},卡号:{2},前门:{3},后门:{4}", ownerInfos[0].personName, mac_add, cardno.ToString(), ownerInfos[0].frontFloor, ownerInfos[0].backFloor, ownerInfos[0].personID);
                                    string url_1 = string.Format("http://{0}:{1}/api/cems/InsertLog", compass_add, compass_port);
                                    string msg_1 = HttpClientPost(url_1, info_insert);
                                    LogHelper.Log("推送刷卡信息" + msg_1);
                                }
                                catch (Exception ex)
                                {
                                    LogHelper.Log("推送刷卡信息异常" + ex.ToString());
                                }

                                try
                                {
                                    if (insert_flag)
                                    {
                                        CardInfoDAL da = new CardInfoDAL();
                                        PersonSnyc personSnyc = new PersonSnyc();
                                        personSnyc.personType = ownerInfos[0].personType;
                                        personSnyc.personName = ownerInfos[0].personName;
                                        personSnyc.sex = ownerInfos[0].sex;
                                        personSnyc.cardNo = ownerInfos[0].cardNo;
                                        personSnyc.frontFloor = ownerInfos[0].frontFloor;
                                        personSnyc.backFloor = ownerInfos[0].backFloor;
                                        personSnyc.startTime = ownerInfos[0].startTime.ToString("yyyy-MM-dd HH:mm:ss");
                                        personSnyc.endTime = ownerInfos[0].endTime.ToString("yyyy-MM-dd HH:mm:ss");
                                        personSnyc.personID = ownerInfos[0].personID;
                                        bool resylt = da.InsertPerson(personSnyc);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    LogHelper.Log("插入用户数据异常" + ex.ToString());
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Log("处理数据异常信息" + ex.ToString());
                }

            }
            catch (Exception ex)
            {
                LogHelper.Log("接收数据异常" + ex.ToString());
            }
            SerialPortRecvTimerS0_1.Start();
        }

        public int GetFloorNum(byte[] data)
        {
            int num = 0;
            string all_data = ToHexStrFromByte(data).PadLeft(80, '0');
            for (int i = 0; i < 80; i++)
            {
                if (all_data.Substring(i, 1) == "1")
                {
                    num++;
                }
            }
            return num;
        }

        public byte ADD(byte[] data)
        {
            int sum = 0;
            for (int i = 0; i < data.Length; i++)
            {
                sum += data[i];
            }
            sum = sum % 256;

            byte a = (byte)sum;

            return a;
        }

        public string ToHexStrFromByte(byte[] byteDatas)
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < byteDatas.Length; i++)
            {

                builder.Append(Convert.ToString(byteDatas[i], 2));
            }
            return builder.ToString().Trim();

        }
        #endregion

        public byte[] HexStringToByteArray(string hexString)
        {
            if (hexString == null)
                throw new ArgumentNullException(nameof(hexString));

            if (hexString.Length % 2 != 0)
                throw new ArgumentException("十六进制字符串的长度必须是偶数。", nameof(hexString));

            byte[] byteArray = new byte[hexString.Length / 2];
            for (int i = 0; i < byteArray.Length; i++)
            {
                string sub = hexString.Substring(i * 2, 2);
                byteArray[byteArray.Length - 1 - i] = Convert.ToByte(sub, 16);
            }
            return byteArray;
        }

        // byte转字符串
        public static string ToHexs(byte[] data)
        {
            if (data.Length <= 0) return "";
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sb.Append(data[i].ToString("X2") + " ");
            }
            string str = sb.ToString();
            return str;
        }

        public bool ttySendMsg(byte[] data)
        {
            try
            {
                myS0SerialPort_1.Write(data, 0, data.Length);
                string cmd = ToHexs(data);
                //LogHelper.Log(cmd);
                return true;
            }
            catch (Exception e)
            {
                return false;
            }
        }

        public string HttpClientPost(string url, object datajson)
        {
            try
            {
                HttpClient httpClient = new HttpClient();//http对象
                                                         //表头参数
                httpClient.DefaultRequestHeaders.Accept.Clear();
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                //转为链接需要的格式
                HttpContent httpContent = new JsonContent(datajson);
                //请求
                HttpResponseMessage response = httpClient.PostAsync(url, httpContent).Result;
                if (response.IsSuccessStatusCode)
                {
                    Task<string> t = response.Content.ReadAsStringAsync();
                    if (t != null)
                    {
                        return t.Result;
                    }
                }
            }
            catch
            {

            }
            return "";
        }


        public string HttpstringClientPost(string url, string datajson)
        {
            try
            {
                HttpClient httpClient = new HttpClient();//http对象
                                                         //表头参数
                httpClient.DefaultRequestHeaders.Accept.Clear();
                //httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                //转为链接需要的格式
                HttpContent httpContent = new StringContent(datajson);
                //请求
                HttpResponseMessage response = httpClient.PostAsync(url, httpContent).Result;
                if (response.IsSuccessStatusCode)
                {
                    Task<string> t = response.Content.ReadAsStringAsync();
                    if (t != null)
                    {
                        return t.Result;
                    }
                }
            }
            catch
            {

            }
            return "";
        }
        public string GetLocalMac()
        {
            string macAddress = "";
            try
            {
                foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
                {
                    if (nic.OperationalStatus == OperationalStatus.Up)
                    {
                        macAddress = nic.GetPhysicalAddress().ToString();
                        IPInterfaceProperties ipProperties = nic.GetIPProperties();
                        UnicastIPAddressInformation curIP = ipProperties.UnicastAddresses[0];
                        string ip = curIP.Address.ToString();
                        string mask = curIP.IPv4Mask.ToString();
                        string server = ipProperties.GatewayAddresses[0].Address.ToString();
                        break;
                    }
                }
                return macAddress;
            }
            catch
            {
                return "";
            }
        }

        #region 连接Compass平台

        public string compass_add = string.Empty;
        public int compass_port = 0;

        public static CancellationTokenSource dt_tokenSource = new CancellationTokenSource();
        public CancellationToken dt_token = dt_tokenSource.Token;
        public ManualResetEvent dt_resetEvent = new ManualResetEvent(true);

        public void CompassHeart()
        {
            Task t = Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    try
                    {
                        HeratInfo heratInfo = new HeratInfo();
                        heratInfo.deviceID = mac_add;
                        heratInfo.timestamp = (int)DateTimeOffset.Now.ToUnixTimeSeconds();
                        string url = string.Format("http://{0}:{1}/api/cems/Heart", compass_add, compass_port);
                        string msg = HttpClientPost(url, heratInfo);
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Log("发送心跳异常" + ex.ToString());
                    }

                    Task.Delay(10000).Wait();
                }
            });
            //try
            //{
            //    Task task = new Task(async () =>
            //    {
            //        if (dt_token.IsCancellationRequested)
            //        {
            //            return;
            //        }
            //        dt_resetEvent.WaitOne();
            //        //do something
            //        DateTime startTime = DateTime.Now;
            //        while (true)
            //        {
            //            try
            //            {
            //                TimeSpan secondSpan = new TimeSpan(DateTime.Now.Ticks - startTime.Ticks);
            //                if (secondSpan.TotalMilliseconds > 5000)
            //                {
            //                    try
            //                    {
            //                        startTime = DateTime.Now;
            //                        HeratInfo heratInfo = new HeratInfo();
            //                        heratInfo.deviceID = mac_add;
            //                        heratInfo.timestamp = (int)DateTimeOffset.Now.ToUnixTimeSeconds();
            //                        LogHelper.Log(JsonConvert.SerializeObject(heratInfo));
            //                        string url = string.Format("http://{0}:{1}/api/cems/Heart", compass_add, compass_port);
            //                        string msg = HttpClientPost(url, heratInfo);
            //                        LogHelper.Log(msg);
            //                    }
            //                    catch (Exception ex)
            //                    {
            //                        LogHelper.Log("发送心跳异常" + ex.ToString());
            //                    }

            //                }
            //            }
            //            catch
            //            {

            //            }
            //        }
            //    }, dt_token);
            //    task.Start();
            //}
            //catch (Exception e)
            //{
            //}
        }

        #endregion
    }
}
